﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Xml;
using System.IO;
using System.Windows.Forms;
using DVDFilmoteka.Settings;
using MovieStorage;

namespace DVDFilmoteka.ServerDatabaseManagement
{
    class CSFDServerDatabase : IServerDatabase
    {
        #region constants
        
        private const String SERVERADDRESS = "http://www.csfd.cz";
        private const String SERVERSEARCHPATH = "/hledani-filmu-hercu-reziseru-ve-filmove-databazi/";
        private const String SERVERQUERY = "search";
        private const String USERAGENT = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
        private const String XMLPATH_SEARCHRESULTS = "//a[text()='{0}']";
        private const String XMLPATH_SEARCHRESULTS2 = "//a[contains(text(),'{0}')]";
                                                   //html/body/table/tbody/tr[2]/td/table/tbody/tr/td[3]/table/tbody/tr/td
        private const String HODNOCENI_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/td[2]/table/tr/td[contains(text(),'%')]";
        private const String ZANRY_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table/tr[last()]/td/table/tr/td[2]/b";
        private const String CESKYNAZEV_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table/tr[last()]/td/table/tr/td[2]/h1";
        private const String ORIGINALNAZEV_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table/tr[last()]/td/table/tr/td[2]/table[last()]/tr/td[2]";

        private const String PICTURE_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table/tr[2]/td/table/tr/td/table";
        private const String YEAR_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table/tr[last()]/td/table/tr/td[2]/b";
        private const String DIRECTOR_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table/tr[2]/td/table/tr/td[2]/a";
        private const String COUNTRY_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table/tr[last()]/td/table/tr/td[2]/b";
        private const String ACTORS_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table/tr[2]/td/table/tr/td[2]/a[contains(@href,'herec')]";
        private const String LENGTH_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table/tr[last()]/td/table/tr/td[2]/b";
        private const String RECENZE_XPATH = "/span/html/body/table/tr[2]/td/table/tr/td/table[2]/tr/td/span/span[2]/div[2]";

        #endregion

        
        /// <summary>
        /// Vrati adresu stranky s konkretnim filmem
        /// </summary>
        /// <returns>Adresa stranky s filmem</returns>
        private String getFilmPage(String filmName)
        {
            // Ziskat stranku ze serveru
            WebClient client = new WebClient();
            client.Encoding = Encoding.UTF8;
            client.QueryString.Add(SERVERQUERY, filmName);
            client.Headers.Add("user-agent", USERAGENT);
            if (SettingsManager.Instance.UseProxy)
            {
                if (!SettingsManager.Instance.UseDefaultProxy)
                {
                    WebProxy proxy = new WebProxy(SettingsManager.Instance.ProxyIPAddress.ToString(),
                                                  SettingsManager.Instance.ProxyPort);
                    client.Proxy = proxy;
                } else
                {
                    client.Proxy = WebRequest.GetSystemWebProxy();
                }
            }

            byte[] data;
            try
            {
                data = client.DownloadData(SERVERADDRESS + SERVERSEARCHPATH);
            }
            catch (Exception e)
            {
                MessageBox.Show("Během přístupu k serveru došlo k vyjímce: " + e.Message);
                return null;
            }
            String readData = client.Encoding.GetString(data);
            readData = readData.ToLower();

            const string href = "window.location.href=";
            if (readData.Contains(href))
            {
                readData = readData.Substring(readData.IndexOf(href) + href.Length + 1);
                readData = readData.Substring(0, readData.IndexOf("'"));
                return SERVERADDRESS + readData;
            }

            // Prevest HTML stranku na XML
            XmlDocument document = convertHtmlToXml(readData);            

            // Vyhledat odkaz na stranku s filmem
            String xpath = String.Format(XMLPATH_SEARCHRESULTS, filmName).ToLower();
            XmlNodeList seznamUzlu = document.SelectNodes(xpath);
            if (seznamUzlu == null || seznamUzlu.Count <= 0)
            {
                xpath = String.Format(XMLPATH_SEARCHRESULTS2, filmName).ToLower();
                seznamUzlu = document.SelectNodes(xpath);
                if (seznamUzlu == null || seznamUzlu.Count <= 0)
                {
                    return null;
                }
            }

            // Prhlidnout vsechny nody a najit ten spravny
            String redirect = null;
            foreach (XmlNode uzel in seznamUzlu)
            {
                if (uzel.Attributes.GetNamedItem("href") != null && !String.IsNullOrEmpty(uzel.Attributes.GetNamedItem("href").Value))
                {
                    redirect = uzel.Attributes.GetNamedItem("href").Value;
                    break;
                }
            }
            if (String.IsNullOrEmpty(redirect)) return null;

            return SERVERADDRESS + redirect;            
        }

        #region IServerDatabase Members

        /// <summary>
        /// Nacte udaje o filmu podle zadaneho jmena
        /// </summary>
        /// <param name="filmName"></param>
        /// <returns></returns>
        public MovieDataStore12 getFilmData(String filmName)
        {         
            return getFilmDataFromLink(getFilmPage(filmName));
        }

        /// <summary>
        /// Nacte udaje o filmu podle zadane adresy
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public MovieDataStore12 getFilmDataFromLink(String address)
        {
            if (address == null) return null;

            // Prejit na stranku konkretniho filmu
            WebClient client = new WebClient();
            client.Encoding = Encoding.UTF8;
            client.Headers.Add("user-agent", USERAGENT);
            if (SettingsManager.Instance.UseProxy)
            {
                if (!SettingsManager.Instance.UseDefaultProxy)
                {
                    WebProxy proxy = new WebProxy(SettingsManager.Instance.ProxyIPAddress.ToString(),
                                                  SettingsManager.Instance.ProxyPort);
                    client.Proxy = proxy;
                }
                else
                {
                    client.Proxy = WebRequest.GetSystemWebProxy();
                }
            }
            
            byte[] data;
            try
            {                
                data = client.DownloadData(address);
            }
            catch (Exception)
            {
                return null;
            }
            String readData = client.Encoding.GetString(data);

            // Prevest HTML stranku na XML
            XmlDocument document = convertHtmlToXml(readData);

            return loadDataFromXML(document, address);
        }

        /// <summary>
        /// Nacte z XML dokumentu udaje o filmu
        /// </summary>
        /// <param name="document"></param>
        /// <param name="linkToFilmPage"></param>
        /// <returns></returns>
        private MovieDataStore12 loadDataFromXML(XmlDocument document, String linkToFilmPage)
        {
            if (document != null)
            {
                MovieDataStore12 dataStore = new MovieDataStore12();
                dataStore.link = linkToFilmPage;
                
                // Hodnoceni
                XmlNodeList list = document.SelectNodes(HODNOCENI_XPATH);
                if (list != null && list.Count > 0)
                {
                    dataStore.csfdRating = list[0].FirstChild.Value;
                    if (dataStore.csfdRating == null) //Kdyz je film v 200 nejlepsich tak je hodnoceni posunute
                    {
                        list = document.SelectNodes(HODNOCENI_XPATH);
                        if (list != null && list.Count > 0)
                        {
                            dataStore.csfdRating = list[0].FirstChild.Value;
                        }
                    }
                    if (dataStore.csfdRating != null && dataStore.csfdRating.Contains("%"))
                    {
                        dataStore.csfdRating = dataStore.csfdRating.Trim();
                    }
                    else
                    {
                        dataStore.csfdRating = "N/A";
                    }
                } else
                {
                    dataStore.csfdRating = "N/A";
                }

                //Zanry
                list = document.SelectNodes(ZANRY_XPATH);
                if (list != null && list.Count > 0)
                {
                    XmlNode node = list[0];
                    String text = node.FirstChild.Value;

                    String[] zanry = text.Split('/');

                    List<String> zanrList = new List<string>();
                    List<String> _zanrList = Form1Servant.loadDataFromXML(Form1Servant.CONFIG, "//root/mzanr/*");
                    foreach (String item in _zanrList)
                    {
                        zanrList.Add(item.ToLower());
                    }

                    // Hlavni zanr
                    String zanrName = zanry[0].Trim().ToLower();
                    if (zanrName.Contains("&"))
                    {
                        zanrName = zanrName.Substring(0, zanrName.IndexOf("&"));
                    }
                    int pos = zanrList.IndexOf(zanrName);                    
                    dataStore.otherGenre.Add(pos);
                    dataStore.mainGenre = pos != -1 ? _zanrList[pos] : "Nezařazeno";

                    // Vedlejsi zanry
                    for (int i = 1; i < zanry.Length; i++)
                    {
                        zanrName = zanry[i].Trim().ToLower();
                        if (zanrName.Contains("&")) //Text byva ukoncen nejakym XML znakem
                        {
                            zanrName = zanrName.Substring(0, zanrName.IndexOf("&"));
                        }
                        pos = zanrList.IndexOf(zanrName);
                        dataStore.otherGenre.Add(pos);
                    }                   
                }

                //Cesky nazev
                list = document.SelectNodes(CESKYNAZEV_XPATH);
                if (list != null && list.Count > 0)
                {
                    XmlNode node = list[0];
                    String text = node.FirstChild.Value;

                    dataStore.czechName = text.Trim();
                }
                else
                {
                    dataStore.czechName = "";
                }

                //Original nazev
                list = document.SelectNodes(ORIGINALNAZEV_XPATH); //Na normalnim miste
                if (list != null && list.Count > 0)
                {
                    XmlNode node = list[0];
                    String text = node.FirstChild.Value;

                    dataStore.originalName = text.Trim();
                }
                else
                {
                    dataStore.originalName = dataStore.czechName;
                }

                // Obrazek
                list = document.SelectNodes(PICTURE_XPATH); //Na normalnim miste
                if (list != null && list.Count > 0)
                {
                    XmlNode node = list[0];
                    String text = node.Attributes.GetNamedItem("background").Value;
                    
                    dataStore.pictureLink = text;
                }
                else
                {
                    dataStore.pictureLink = "";
                }

                // Zeme, Delka, Rok
                list = document.SelectNodes(COUNTRY_XPATH);
                if (list != null && list.Count > 0)
                {
                    XmlNode node = list[0];
                    if (node.ChildNodes.Count >= 3)
                    {
                        String text = node.ChildNodes[2].Value.Trim();

                        String[] datas = text.Split(',');

                        if (datas.Length > 0) dataStore.country = datas[0].Trim();
                        if (datas.Length > 1) dataStore.year = datas[1].Trim();
                        if (datas.Length > 2) dataStore.length = datas[2].Trim();
                    }
                    else
                    {
                        dataStore.country = "";
                        dataStore.length = "";
                        dataStore.year = "";
                    }
                }
                else
                {
                    dataStore.country = "";
                    dataStore.length = "";
                    dataStore.year = "";
                }

                // Reziser
                list = document.SelectNodes(DIRECTOR_XPATH);
                if (list != null && list.Count > 0)
                {
                    XmlNode node = list[0];
                    String text = node.FirstChild.Value;

                    dataStore.directorName = text.Replace("&nbsp;", " ").Trim();
                    if (node.Attributes["href"] != null)
                    {
                        dataStore.directorLink = "http://www.csfd.cz" + node.Attributes["href"].Value;
                    }
                    else
                    {
                        dataStore.directorLink = "";
                    }
                }
                else
                {
                    dataStore.directorName = "";
                    dataStore.directorLink = "";
                }

                // Herci
                list = document.SelectNodes(ACTORS_XPATH);
                if (list != null && list.Count > 0)
                {
                    foreach (XmlNode node in list)
                    {
                        String name = node.FirstChild.Value;
                        String link = "";

                        name = name.Replace("&nbsp;", " ").Trim();
                        if (node.Attributes["href"] != null)
                        {
                            link = "http://www.csfd.cz" + node.Attributes["href"].Value;
                        }
                        else
                        {
                            link = "";
                        }

                        if (!String.IsNullOrEmpty(name))
                        {
                            dataStore.actors.Add(name, link);
                        }
                    }
                }
                else
                {
                    dataStore.actors = new SerializableDictionary<string, string>();                    
                }

                // Recenze
                list = document.SelectNodes(RECENZE_XPATH);
                if (list != null && list.Count > 0)
                {
                    XmlNode node = list[0];
                    String text = node.FirstChild.Value;

                    dataStore.recenze = text.Trim().Replace("&nbsp;(", "");
                }
                else
                {
                    dataStore.recenze = "";
                }

                return dataStore;
            }
            return null;
        }

        /// <summary>
        /// Prevede HTML kod na XML
        /// </summary>
        /// <returns></returns>
        private XmlDocument convertHtmlToXml(String readData)
        {
            String tempDir = Environment.GetEnvironmentVariable("TEMP");
            if (String.IsNullOrEmpty(tempDir))
            {
                tempDir = Environment.GetEnvironmentVariable("TMP");
            }

            if (String.IsNullOrEmpty(tempDir))
            {
                tempDir = Environment.SpecialFolder.ApplicationData.ToString();
            }

            HtmlAgilityPack.HtmlDocument htmlDocument = new HtmlAgilityPack.HtmlDocument();
            htmlDocument.LoadHtml(readData);
            htmlDocument.OptionOutputAsXml = true;

            htmlDocument.Save(tempDir + "//temp.xml", Encoding.UTF8);

            XmlDocument document = new XmlDocument();
            document.Load(tempDir + "//temp.xml");
            File.Delete(tempDir + "//temp.xml");

            return document;
        }

        #endregion
    }
}